package com.lianqi.emcpframework.core.exception;

import com.lianqi.emcpframework.core.exception.international.InternationalAble;
import com.lianqi.emcpframework.core.exception.international.LocaleMessageProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import java.io.PrintWriter;
import java.io.Serializable;
import java.util.*;

/**
 * @program emcp-framework
 * @ClassName ExcepFactor
 * @description: 异常门面类
 * @author: sky
 * @create: 2019/03/28 16:37
 */
public class ExcepFactor implements Serializable, InternationalAble {


    protected static final Logger LOGGER = LoggerFactory.getLogger(ExcepFactor.class);
    public static final int ERROR_LEVEL_SYSTEM = 1;
    public static final int ERROR_LEVEL_SERVICE = 2;
    private final HttpStatus httpStatus;
    private final int level;
    private final int serviceId;
    private final int errorCode;
    private final String errorMsg;
    private LocaleMessageProvider messageProvider;

    public static final int MAX_ERROR_CODE = 99;

    public void setMessageProvider(LocaleMessageProvider messageProvider) {
        this.messageProvider = messageProvider;
    }

    private static final Set<ExcepFactor> excepFactors;

    static {
        excepFactors = new HashSet<>();
    }


    private ExcepFactor(int level, int serviceId, HttpStatus httpStatus,
                        int errorCode, String errorMsg) {
        if (errorCode < 0 || errorCode > MAX_ERROR_CODE) {
            throw new IllegalArgumentException("errorCode must between 1 and 99.");
        }
        if (serviceId < 0 || serviceId > MAX_ERROR_CODE) {
            throw new IllegalArgumentException("serviceId must between 1 and 99.");
        }
        this.httpStatus = httpStatus;
        this.level = level;
        this.serviceId = serviceId;
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;

        if (excepFactors.contains(this)) {
            throw new IllegalArgumentException("Exception stack exists this :" + this.getErrorCode());
        }
        excepFactors.add(this);
    }

    protected ExcepFactor(int serviceId, HttpStatus httpStatus,
                          int errorCode, String errorMsg) {
        this(ERROR_LEVEL_SERVICE, serviceId, httpStatus, errorCode, errorMsg);
    }

    public static void printException(PrintWriter out) {
        List<ExcepFactor> excepFactorList = new ArrayList<>(excepFactors);
        Collections.sort(excepFactorList, new Comparator<ExcepFactor>() {
            @Override
            public int compare(ExcepFactor o1, ExcepFactor o2) {
                return o1.getErrorCode() - o2.getErrorCode();
            }
        });
        for (ExcepFactor e : excepFactorList) {
            out.println(e.toString());
            out.flush();
        }
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    public int getErrorCode() {
        return this.level * 10000 + this.serviceId * 100 + this.errorCode;
    }

    public String getErrorMsg() {
        return getErrorMsg(null);
    }

    public String getErrorMsg(Object... args) {
        if (args == null || args.length == 0) {
            return errorMsg;
        }
        try {
            return String.format(errorMsg, args);
        } catch (Exception e) {
            LOGGER.error("getErrorMsg", e);
            return errorMsg;
        }
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.getErrorCode();
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        ExcepFactor other = (ExcepFactor) obj;
        if (this.getErrorCode() != other.getErrorCode()) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return String.format("%s\t%s", this.getErrorCode(), this.getErrorMsg());
    }


    public static final ExcepFactor E_DEFAULT = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.INTERNAL_SERVER_ERROR, 1, "对不起,服务器内部发生错误,请稍后再试.");

    /**
     * 服务端资源不可用
     */
    public static final ExcepFactor E_SERVICE_UNAVAILABLE = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.SERVICE_UNAVAILABLE, 2, "服务端资源不可用!");
    public static final ExcepFactor E_DEPENDENCE_SERVICE_UNAVAILABLE = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.SERVICE_UNAVAILABLE, 3, "依赖服务不可用!");
    public static final ExcepFactor E_SYSTEM_BUSY = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.SERVICE_UNAVAILABLE, 4, "系统繁忙，请重试!"
    );

    public static final ExcepFactor E_DIGEST_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.SERVICE_UNAVAILABLE, 5, "加解密失败"
    );

    public static final ExcepFactor E_AUTH_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.UNAUTHORIZED, 9, "认证失败"
    );

    /**
     * 接口不存在
     */
    public static final ExcepFactor E_API_NOT_EXIST = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.NOT_FOUND, 10,
            "接口不存在!");
    /**
     * Http 方法错误
     */
    public static final ExcepFactor E_METHOD_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.METHOD_NOT_ALLOWED, 11,
            "请求的HTTP METHOD不支持!");
    /**
     * 接口已经废弃
     */
    public static final ExcepFactor E_API_DEPRECATED_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.SERVICE_UNAVAILABLE, 12, "该接口已经废弃");

    /**
     *  http协议以及参数类错误
     */
    public static final ExcepFactor E_UNSUPPORT_MEDIATYPE_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.UNSUPPORTED_MEDIA_TYPE, 13, "不支持的 MediaType (%s).");
    public static final ExcepFactor E_PARAM_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.BAD_REQUEST, 14, "错误:参数错误，请参考API文档!");
    public static final ExcepFactor E_ILLEGAL_REQUEST = new ExcepFactor(ERROR_LEVEL_SYSTEM, 0,
            HttpStatus.BAD_REQUEST, 15, "非法请求！");
    public static final ExcepFactor E_PARAM_MISS_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.BAD_REQUEST, 16,
            "错误:缺失必选参数:%s，请参考API文档.");
    public static final ExcepFactor E_PARAM_INVALID_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM,
            0,
            HttpStatus.BAD_REQUEST,
            17,
            "错误:参数 (%s) 非法,希望得到 (%s),实际得到 (%s)，请参考API文档.");
    public static final ExcepFactor E_POST_BODY_LENGTH_LIMIT = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.BAD_REQUEST, 18, "请求长度超过限制!");

    /**
     * 来源不对
     */
    public static final ExcepFactor E_CLIENTID_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.BAD_REQUEST, 32, "Client不存在！");

    /** 限制类错误 **/
    /**
     * 用户IP次数达到限制
     */
    public static final ExcepFactor E_IP_OUTOFLIMIT = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.FORBIDDEN, 33, "IP请求超过上限!");
    /**
     * 用户请求次数达到限制
     */
    public static final ExcepFactor E_USER_OUTOFLIMIT = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.FORBIDDEN, 34, "用户请求超过上限!");
    /**
     * 用户对特定接口的请求次数达到限制
     */
    public static final ExcepFactor E_API_OUTOFLIMIT = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.FORBIDDEN, 35, "用户请求接口%s超过上限!");
    /**
     * 非法用户
     */
    public static final ExcepFactor E_USER_NOTOPEN = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.FORBIDDEN, 50, "不合法的用户!");
    public static final ExcepFactor E_ENTITY_NOT_FOUND = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.NOT_FOUND, 51, "所查询的对象不存在");

    /**
     * 实体字段校验
     */
    public static final ExcepFactor E_BEAN_VALIDATE_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.BAD_REQUEST, 60, "实体字段校验失败");

    /**
     * 实体创建
     */
    public static final ExcepFactor E_ENTITY_CREATE_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.INTERNAL_SERVER_ERROR, 61, "实体创建失败");

    /**
     * 实体创建
     */
    public static final ExcepFactor E_ENTITY_UPDATE_ERROR = new ExcepFactor(
            ERROR_LEVEL_SYSTEM, 0, HttpStatus.INTERNAL_SERVER_ERROR, 62, "实体更新失败");


    @Override
    public String localeMessage(Object... args) {

        String localeMsg = null;
        try {
            localeMsg = messageProvider.getMessage(String.valueOf(this.getErrorCode()), args);
        } catch (Exception e) {
            LOGGER.error("parser to locale Message error:" + e.getMessage());
        }
        if (localeMsg == null) {
            localeMsg = this.getErrorMsg(args);
        }
        return localeMsg;
    }

}
